﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection.Emit;
using System.Collections.Concurrent;

namespace DotNetImage.Util
{
    public static class TypeHelper
    {
        private static readonly ConcurrentDictionary<Type, int>_cache = new ConcurrentDictionary<Type, int>();

        private static readonly ConcurrentDictionary<Type, uint> _maxValue = new ConcurrentDictionary<Type, uint>();

        private static readonly ConcurrentDictionary<Type, uint> _minValue = new ConcurrentDictionary<Type, uint>();

        static TypeHelper()
        {
            //_maxValue.AddOrUpdate(typeof(byte), byte.MaxValue);
        }


        public static int SizeOf<T>(T? obj) where T : struct
        {
            if (obj == null) throw new ArgumentNullException("obj");
            return SizeOf(typeof(T?));
        }

        public static int SizeOf<T>(T obj)
        {
            if (obj == null) throw new ArgumentNullException("obj");
            return SizeOf(obj.GetType());
        }

        public static int SizeOf(Type t)
        {
            if (t == null) throw new ArgumentNullException("t");

            return _cache.GetOrAdd(t, t2 =>
            {
                var dm = new DynamicMethod("$", typeof(int), Type.EmptyTypes);
                ILGenerator il = dm.GetILGenerator();
                il.Emit(OpCodes.Sizeof, t2);
                il.Emit(OpCodes.Ret);

                var func = (Func<int>)dm.CreateDelegate(typeof(Func<int>));
                return func();
            });
        }

/*
        public static uint MaxValue(Type t)
        {
            if (t == null) throw new ArgumentNullException("t");
            return _maxValue.GetOrAdd(t, t2 =>
            {
                int size = TypeHelper.SizeOf(t);
                switch (size)
                {
                    case 1:
                        t2 = (uint)byte.MaxValue;
                        break;
                    case 2:
                        t2 = (uint)ushort.MaxValue;
                        break;
                    case 4:
                        t2 = (uint)uint.MaxValue;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException(t.ToString());
                }
                ILGenerator il = dm.GetILGenerator();
                il.Emit(OpCodes., t2);
                il.Emit(OpCodes.Ret);

            });
        }
 */

    
    }
}
